using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using AutoMapper;
using Core.Db.Dtos;
using Core.Db.Helper;
using Core.Db.Models;
using Core.Db.ResourceParameters;
using Core.Db.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;

namespace Core.API.Controllers;

/// <summary>
/// 旅游路线
/// </summary>
[Route("/api/[controller]")]
[ApiController]
public class TouristRoutesController : ControllerBase
{
    private readonly ITouristRouteRepository _routeRepository;
    private readonly IMapper _mapper;
    private readonly IProPertyMappingService _proPertyMappingService;
    private readonly IUrlHelper _urlHelper;

    public TouristRoutesController(ITouristRouteRepository routeRepository, IMapper mapper, IUrlHelperFactory urlHelperFactory, IActionContextAccessor accessor,
        IProPertyMappingService proPertyMappingService)
    {
        _routeRepository = routeRepository;
        _mapper = mapper;
        _proPertyMappingService = proPertyMappingService;
        _urlHelper = urlHelperFactory.GetUrlHelper(accessor.ActionContext);
    }

    private string GenerateTouristRouteResourceURL(
        TouristRouteResourceParamaters paramaters,
        PaginationResourceParamaters paramaters2,
        ResourceUriType type)
    {
        return type switch
        {
            ResourceUriType.PreviousPage => _urlHelper.Link("GetTouristRoutes", new
            {
                fields = paramaters.Fields,
                orderBy = paramaters.OrderBy,
                keyword = paramaters.Keyword,
                rating = paramaters.Rating,
                pageNumber = paramaters2.PageNumber - 1,
                pageSize = paramaters2.PageSize
            }),
            ResourceUriType.NextPage => _urlHelper.Link("GetTouristRoutes", new
            {
                fields = paramaters.Fields,
                orderBy = paramaters.OrderBy,
                keyword = paramaters.Keyword,
                rating = paramaters.Rating,
                pageNumber = paramaters2.PageNumber + 1,
                pageSize = paramaters2.PageSize
            }),
            _ => _urlHelper.Link("GetTouristRoutes", new
            {
                fields = paramaters.Fields,
                orderBy = paramaters.OrderBy,
                keyword = paramaters.Keyword,
                rating = paramaters.Rating,
                pageNumber = paramaters2.PageNumber,
                pageSize = paramaters2.PageSize
            }),
        };
    }

    /// <summary>
    /// 获取旅游路线
    /// </summary>
    /// <param name="paramaters"></param>
    /// <param name="paramaters2"></param>
    /// <param name="mediaType"></param>
    /// <returns></returns>
    // application/vnd.unitysir.hateoas+json
    [HttpGet(Name = "GetTouristRoutes")]
    public async Task<IActionResult> GetTouristRoutes(
        [FromQuery] TouristRouteResourceParamaters paramaters,
        [FromQuery] PaginationResourceParamaters paramaters2,
        [FromHeader(Name = "Accept")] string mediaType)
    {
        if (MediaTypeHeaderValue.TryParse(mediaType, out MediaTypeHeaderValue parseMediatype) == false)
        {
            return BadRequest();
        }

        if (_proPertyMappingService.IsMappingExists<TouristRouteDto, TouristRoute>(paramaters.OrderBy) == false)
        {
            return BadRequest("请输入正确的排序参数");
        }

        if (_proPertyMappingService.IsPropertiesExists<TouristRouteDto>(paramaters.Fields) == false)
        {
            return BadRequest("请输入正确的塑性参数");
        }

        var touristRoutesFromRepo = await _routeRepository
            .GetTouristRoutesAsync(
                paramaters.Keyword,
                paramaters.RatingOperator,
                paramaters.RatingValue,
                paramaters2.PageSize,
                paramaters2.PageNumber,
                paramaters.OrderBy);
        if (touristRoutesFromRepo == null || touristRoutesFromRepo.Count() <= 0)
        {
            return NotFound("没有找到旅游路线");
        }

        var torusitRoutesDto = _mapper.Map<IEnumerable<TouristRouteDto>>(touristRoutesFromRepo);

        var previousPageLink = touristRoutesFromRepo.HasPrevious ? GenerateTouristRouteResourceURL(paramaters, paramaters2, ResourceUriType.PreviousPage) : null;
        var nextPageLink = touristRoutesFromRepo.HasNext ? GenerateTouristRouteResourceURL(paramaters, paramaters2, ResourceUriType.NextPage) : null;

        //x-pagination
        var paginationMetadata = new
        {
            previousPageLink,
            nextPageLink,
            totalCount = touristRoutesFromRepo.TotalCount,
            pageSize = touristRoutesFromRepo.PageSize,
            currentPage = touristRoutesFromRepo.CurrentPage,
            totalPages = touristRoutesFromRepo.TotalPages,
        };

        Response.Headers.Add("x-pagination", JsonConvert.SerializeObject(paginationMetadata));

        var shapedDtoList = torusitRoutesDto.ShapeData(paramaters.Fields);

        if (parseMediatype.MediaType == "application/vnd.unitysir.hateoas+json")
        {
            var linkDto = CreateLinksForTouristRouteList(paramaters, paramaters2);

            var shapedDtoWithLinkList = shapedDtoList.Select(t =>
            {
                var touristRouteDictionary = t as IDictionary<string, object>;
                var links = CreateLinkForTouristRoute((Guid)touristRouteDictionary["Id"], null);
                touristRouteDictionary.Add("links", links);
                return touristRouteDictionary;
            });

            var result = new
            {
                value = shapedDtoWithLinkList,
                links = linkDto,
            };

            return Ok(result);
        }

        return Ok(shapedDtoList);
    }

    private IEnumerable<LinkDto> CreateLinksForTouristRouteList(
        TouristRouteResourceParamaters paramaters,
        PaginationResourceParamaters paramaters2)
    {
        var links = new List<LinkDto>();

        //添加self，自我链接
        links.Add(new LinkDto(GenerateTouristRouteResourceURL(paramaters, paramaters2, ResourceUriType.CurrentPage), "self", "GET"));

        // "api/touristRoutes"
        links.Add(new LinkDto(Url.Link("CreateTouristRoute", null), "create_tourist_route", "POST"));

        return links;
    }

    [HttpGet("{touristRouteId:guid}", Name = "GetTouristRouteById")]
    public async Task<IActionResult> GetTouristRouteById(Guid touristRouteId, string? fileds)
    {
        if (_proPertyMappingService.IsPropertiesExists<TouristRouteDto>(fileds) == false)
        {
            return BadRequest("请输入正确的塑性参数");
        }

        var touristRouteFromPepo = await _routeRepository.GetTouristRouteAsync(touristRouteId);
        if (touristRouteFromPepo == null)
        {
            return NotFound($"没有找到旅游路线:{touristRouteId}");
        }

        var touristRouteDto = _mapper.Map<TouristRouteDto>(touristRouteFromPepo);
        // return Ok(touristRouteDto.ShapeData(fileds));

        var linkDtos = CreateLinkForTouristRoute(touristRouteId, fileds);
        var result = touristRouteDto.ShapeData(fileds) as IDictionary<string, object>;
        result.Add("Links", linkDtos);

        return Ok(result);
    }

    private IEnumerable<LinkDto> CreateLinkForTouristRoute(Guid touristRouteId, string? fileds)
    {
        var links = new List<LinkDto>();
        //获取
        links.Add(new LinkDto(Url.Link("GetTouristRouteById", new { touristRouteId, fileds }), "self", "GET"));
        //更新
        links.Add(new LinkDto(Url.Link("UpdateToruistRoute", new { touristRouteId }), "update", "PUT"));
        //局部更新
        links.Add(new LinkDto(Url.Link("PartiallyUpdateToursitRoute", new { touristRouteId }), "partially_update", "PATCH"));
        //删除
        links.Add(new LinkDto(Url.Link("DeleteTouristRoute", new { touristRouteId }), "delete", "DELETE"));

        //获取路线图片
        links.Add(new LinkDto(Url.Link("GetPictureListForTouristRoute", new { touristRouteId }), "get_pictures", "GET"));
        //添加新图片
        links.Add(new LinkDto(Url.Link("CreateTouristRoutePicture", new { touristRouteId }), "create_picture", "POST"));


        return links;
    }


    // [Authorize(AuthenticationSchemes = "Bearer")]
    // [Authorize(Roles = "Admin")]
    [HttpPost(Name = "CreateTouristRoute")]
    public async Task<IActionResult> CreateTouristRoute([FromBody] TouristRouteForCreationDto touristRouteForCreationDto)
    {
        var touristRouteModel = _mapper.Map<TouristRoute>(touristRouteForCreationDto);
        await _routeRepository.AddTouristRouteAsync(touristRouteModel);
        await _routeRepository.SaveAsync();
        var touristRouteReturn = _mapper.Map<TouristRouteDto>(touristRouteModel);

        var links = CreateLinkForTouristRoute(touristRouteModel.Id, null);
        var result = touristRouteReturn.ShapeData(null) as IDictionary<string, object>;
        result.Add("Links", links);

        return CreatedAtRoute("GetTouristRouteById", new { touristRouteId = result["Id"] }, result);
    }

    [Authorize(AuthenticationSchemes = "Bearer")]
    [Authorize(Roles = "Admin")]
    [HttpPut("{touristRouteId}", Name = "UpdateToruistRoute")]
    public async Task<IActionResult> UpdateToruistRoute(
        [FromRoute] Guid touristRouteId,
        [FromBody] TouristRouteForUpdateDto touristRouteForUpdateDto
    )
    {
        if (await _routeRepository.TouristRouteExistAsync(touristRouteId) == false)
        {
            return NotFound("旅游路线未找到");
        }

        var touristRouteFromRepo = await _routeRepository.GetTouristRouteAsync(touristRouteId);
        // 1.映射Dto
        // 2.更新Dto
        // 3映射Model
        _mapper.Map(touristRouteForUpdateDto, touristRouteFromRepo);
        await _routeRepository.SaveAsync();
        return NoContent();
    }

    [Authorize(AuthenticationSchemes = "Bearer")]
    [Authorize(Roles = "Admin")]
    [HttpPatch("{touristRouteId}", Name = "PartiallyUpdateToursitRoute")]
    public async Task<IActionResult> PartiallyUpdateToursitRoute(
        [FromRoute] Guid touristRouteId,
        [FromBody] JsonPatchDocument<TouristRouteForUpdateDto> patchDocument
    )
    {
        if (await _routeRepository.TouristRouteExistAsync(touristRouteId) == false)
        {
            return NotFound("旅游路线未找到");
        }

        var touristRouteRepo = await _routeRepository.GetTouristRouteAsync(touristRouteId);
        var touristRouteToPatch = _mapper.Map<TouristRouteForUpdateDto>(touristRouteRepo);
        patchDocument.ApplyTo(touristRouteToPatch, ModelState);
        if (TryValidateModel(touristRouteToPatch) == false)
        {
            return ValidationProblem(ModelState);
        }

        _mapper.Map(touristRouteToPatch, touristRouteRepo);
        await _routeRepository.SaveAsync();

        return NoContent();
    }

    [Authorize(AuthenticationSchemes = "Bearer")]
    [Authorize(Roles = "Admin")]
    [HttpDelete("{touristRouteId}", Name = "DeleteTouristRoute")]
    public async Task<IActionResult> DeleteTouristRoute([FromRoute] Guid touristRouteId)
    {
        if (await _routeRepository.TouristRouteExistAsync(touristRouteId) == false)
        {
            return NotFound("旅游路线未找到");
        }

        var touristRoute = await _routeRepository.GetTouristRouteAsync(touristRouteId);
        await _routeRepository.DeleteTouristRouteAsync(touristRoute);
        await _routeRepository.SaveAsync();
        return NoContent();
    }

    [Authorize(AuthenticationSchemes = "Bearer")]
    [Authorize(Roles = "Admin")]
    [HttpDelete("({touristIDs})")]
    public async Task<IActionResult> DeleteByIDs(
        [ModelBinder(BinderType = typeof(ArrayModelBinder))] [FromRoute]
        IEnumerable<Guid> touristIDs)
    {
        if (touristIDs == null)
        {
            return BadRequest();
        }

        var touristRoutesFromRepo = await _routeRepository.GetTouristRouteByIDListAsync(touristIDs);
        await _routeRepository.DeleteTouristRoutesAsync(touristRoutesFromRepo);
        await _routeRepository.SaveAsync();
        return NoContent();
    }
}